/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2005-2009 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_StSR176.c
  -------------

  This is the reference applications that shows how to read/write data
  in a STM SR 176 tag.
  
  JDA 21/11/2003 : initial release
  JDA 14/11/2005 : moved code from the DLL to this sample
                   DLL is removed from the SDK because nobody uses it !
  JDA 10/01/2007 : fixed a few warnings when compiling under GCC

*/
#include "products/springprox/springprox.h"

#include <stdio.h>
#include <string.h>

SWORD SPROX_ConfigureForSR176(void);

SWORD SPROX_SR176_Initiate(BYTE * chip);
SWORD SPROX_SR176_Select(BYTE chip);
SWORD SPROX_SR176_Completion(void);
SWORD SPROX_SR176_ReadBlock(BYTE bloc, WORD * data);
SWORD SPROX_SR176_WriteBlock(BYTE bloc, WORD data);
SWORD SPROX_SR176_GetProtection(BYTE * chip, BYTE * locks);
SWORD SPROX_SR176_ProtectBlock(BYTE chip, BYTE locks);
SWORD SPROX_SR176_ReadTagUID(BYTE * picc_uid64);
SWORD SPROX_SR176_ActivateTag(BYTE * chip, BYTE * picc_uid64);


int main(int argc, char **argv)
{
  SWORD rc;
  int i;
  char s_buffer[64];
  BYTE uid[8];
  BYTE cid;
  BYTE bloc;
  WORD data[16];

  char *device = NULL;

  if (argc > 1)
    device = argv[1];

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("S.T. MICROELECTRONICS SR176 reference demo\n");
  printf("------------------------------------------\n");
  printf("www.springcard.com\n\n");

  rc = SPROX_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");

  /* Open reader */
  /* ----------- */

  rc = SPROX_ReaderOpen(device);
  if (rc != MI_OK)
  {
    printf("Reader not found\n");
    goto done;
  }

  rc = SPROX_ReaderGetDevice(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader found on %s\n", s_buffer);

  rc = SPROX_ReaderGetFirmware(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader firwmare is %s\n", s_buffer);

  /* Configure reader for ST memory cards operation */
  /* ---------------------------------------------- */
  rc = SPROX_ConfigureForSR176();
  if (rc != MI_OK)
  {
    printf("Failed to configure the reader\n");
    goto close;
  }

  /* RF field ON */
  SPROX_ControlRF(TRUE);

  /* Select a compliant tag */
  /* ---------------------- */
  rc = SPROX_SR176_ActivateTag(&cid, uid);
  if (rc != MI_OK)
  {
    printf("No compliant tag in RF field\n");
    goto close;
  }

  printf("Tag found: CID=%02X UID=", cid);
  for (i = 0; i < 8; i++)
    printf("%02X", uid[i]);
  printf("\n");

  /* Read blocks 0 to 15 */

  printf("Reading 16 blocks...\n");

  for (bloc = 0; bloc < 16; bloc++)
  {
    rc = SPROX_SR176_ReadBlock(bloc, &data[bloc]);
    if (rc != MI_OK)
    {
      printf("Failed to read block %d\n", bloc);
      goto tag_halt;
    }
    printf("Block %02d : %04X\n", bloc, data[bloc]);
  }

  /* Write blocks 4 to 14 */

  printf("Writing 11 blocks...\n");

  for (bloc = 4; bloc < 15; bloc++)
  {
    rc = SPROX_SR176_WriteBlock(bloc, data[i]);
    if (rc != MI_OK)
    {
      printf("Failed to write block %d\n", bloc);
      goto tag_halt;
    }
    printf("Block %02d : OK\n", bloc);
  }

  goto tag_halt;

tag_halt:
  /* Halt the tag */
  rc = SPROX_SR176_Completion();
  if (rc != MI_OK)
  {
    printf("Failed to halt the tag\n");
    goto close;
  }

close:
  /* Close the reader */
  SPROX_ControlRF(FALSE);
  SPROX_ReaderClose();

done:
  /* Display last error */
  if (rc == MI_OK)
  {
    printf("Done\n");
  } else
  {
    printf("%s (%d)\n", SPROX_GetErrorMessage(rc), rc);
  }
  return 0;
}


/*
 * Configure the reader for ST SR176 operation
 * -------------------------------------------
 */
SWORD SPROX_ConfigureForSR176(void)
{
  SWORD rc;

  /* Enter ISO 14443-B mode */
  rc = SPROX_SetConfig(CFG_MODE_ISO_14443_B);
  if (rc != MI_OK)
    return rc;

  /* Write a magic value into the RC531... */
  rc = WriteRIC(0x17, 0x00);
  if (rc != MI_OK)
    return rc;

  return MI_OK;
}

/*
 * ST SR176 "Initiate" function
 * ----------------------------
 */
SWORD SPROX_SR176_Initiate(BYTE * chipID)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;

  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x06;
  buffer[1] = 0x00;

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 2 + 2, buffer, &length, TRUE, 0xFFFF);

  if (rc == MI_OK)
  {
    if (chipID != NULL)
      *chipID = buffer[0];
  }

  if (rc == MI_INTERFACEERR)
    rc = MI_NOTAGERR;

  return rc;
}

/*
 * ST SR176 "Select" function
 * --------------------------
 */
SWORD SPROX_SR176_Select(BYTE chipID)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;

  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x0E;
  buffer[1] = chipID;

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 2 + 2, buffer, &length, TRUE, 0xFFFF);

  return rc;
}

/*
 * ST SR176 "Completion" function
 * ------------------------------
 */
SWORD SPROX_SR176_Completion(void)
{
  BYTE buffer[200];
  WORD length;

  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x0F;

  length = sizeof(buffer);
  SPROX_B_Exchange(buffer, 1 + 2, buffer, &length, TRUE, 0x1000);

  return MI_OK;
}

/*
 * ST SR176 "Read block" function
 * ------------------------------
 */
SWORD SPROX_SR176_ReadBlock(BYTE blocAddr, WORD * data)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;

  if (blocAddr > 15)
    return MI_LIB_CALL_ERROR;

  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x08;
  buffer[1] = blocAddr;

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 2 + 2, buffer, &length, TRUE, 0x2000);

  if (rc == MI_OK)
  {
    if (data != NULL)
    {
      *data = buffer[1];
      *data *= 0x0100;
      *data += buffer[0];
    }
  }

  return rc;
}

/*
 * ST SR176 "Write block" function
 * -------------------------------
 */
SWORD SPROX_SR176_WriteBlock(BYTE blocAddr, WORD data)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;
  WORD new_data;

  if (blocAddr < 4 || blocAddr > 14)
    return MI_LIB_CALL_ERROR;

  // Writing the data:
  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x09;
  buffer[1] = blocAddr;
  buffer[2] = (BYTE) (data % 0x0100);
  buffer[3] = (BYTE) (data / 0x0100);

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 4 + 2, buffer, &length, TRUE, 0x1000);

  // Verifying if the data were written correctly:
  memset(buffer, 0xCC, sizeof(buffer));

  rc = SPROX_SR176_ReadBlock(blocAddr, &new_data);
  if (rc != MI_OK)
    return rc;

  if (new_data == data)
    return MI_OK;
  else
    return MI_WRITEERR;
}

/*
 * ST SR176 "Get protection" function
 * ----------------------------------
 */
SWORD SPROX_SR176_GetProtection(BYTE * chipID, BYTE * lockReg)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;

  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x08;
  buffer[1] = 0x0F;

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 2 + 2, buffer, &length, TRUE, 0x2000);

  if (rc == MI_OK)
  {
    if (chipID != NULL)
      *chipID = buffer[0];
    if (lockReg != NULL)
      *lockReg = buffer[1];
  }

  return rc;
}

/*
 * ST SR176 "Protect block" function
 * ---------------------------------
 */
SWORD SPROX_SR176_ProtectBlock(BYTE chipID, BYTE lockReg)
{
  BYTE buffer[200];
  SWORD rc;
  WORD length;

  // Changing the access rigths:
  memset(buffer, 0xCC, sizeof(buffer));

  buffer[0] = 0x09;
  buffer[1] = 0x0F;
  buffer[2] = 0x00;
  buffer[3] = lockReg;

  length = sizeof(buffer);
  rc = SPROX_B_Exchange(buffer, 4 + 2, buffer, &length, TRUE, 0x1000);

  // Re-selecting the tag in order to apply the new access condition settings:
  rc = SPROX_SR176_Select(chipID);
  if (rc != MI_OK)
    return rc;

  // Verifying if the access rigths were written correctly:
  memset(buffer, 0xCC, sizeof(buffer));

  rc = SPROX_SR176_GetProtection(buffer, buffer + 1);
  if (rc != MI_OK)
    return rc;

  if (lockReg == buffer[1])
    return MI_OK;
  else
    return MI_WRITEERR;
}

/*
 * ST SR176 : read tag UID (4-first blocks)
 * ----------------------------------------
 */
SWORD SPROX_SR176_ReadTagUID(BYTE * picc_uid64)
{
  WORD data[4];
  SWORD rc;
  BYTE i;

  for (i = 0; i < 4; i++)
  {
    rc = SPROX_SR176_ReadBlock(i, &data[i]);
    if (rc != MI_OK)
      return rc;
  }

  if (picc_uid64 != NULL)
  {
    for (i = 0; i < 4; i++)
    {
      picc_uid64[2 * i] = (BYTE) (data[i] % 0x0100);
      picc_uid64[2 * i + 1] = (BYTE) (data[i] / 0x0100);
    }
  }

  return rc;
}

/*
 * ST SR176 : tag activation sequence
 * ----------------------------------
 */
SWORD SPROX_SR176_ActivateTag(BYTE * chipID, BYTE * picc_uid64)
{
  SWORD rc;
  BYTE id;

  rc = SPROX_SR176_Initiate(&id);
  if (rc != MI_OK)
    return rc;

  rc = SPROX_SR176_Select(id);
  if (rc != MI_OK)
    return rc;

  if (chipID != NULL)
    *chipID = id;

  rc = SPROX_SR176_ReadTagUID(picc_uid64);
  if (rc != MI_OK)
    return rc;

  return rc;
}
